using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input.Touch;
using WindowsPhoneGame1.GamePlayStates;


namespace WindowsPhoneGame1.GameScreens
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public abstract class Screen
    {
        protected enum BState
        {
            HOVER,
            UP,
            JUST_RELEASED,
            DOWN
        }

        protected int NUMBER_OF_BUTTONS,
            BUTTON_HEIGHT = 40,
            BUTTON_WIDTH = 88;

        protected Color background_color;

        protected Color[] button_color;
        protected Boolean[] button_enabled;
        protected Rectangle[] button_rectangle;
        protected BState[] button_state;
        protected Texture2D[] button_texture;
        protected double[] button_timer;
        protected Func<int, int, bool>[] button_functions;

        //mouse pressed and mouse just pressed
        protected bool mpressed, prev_mpressed = false;

        //mouse location in window
        protected int mx, my;
        protected Vector2 touchLocation = new Vector2(-1);

        protected double frame_time;

        protected Game1 game;
        
        

        protected Screen(Game1 game)
        {
            this.game = game;
        }

        public virtual void Initialize()
        {
            button_color = new Color[NUMBER_OF_BUTTONS];
            button_enabled = new Boolean[NUMBER_OF_BUTTONS];
            button_rectangle = new Rectangle[NUMBER_OF_BUTTONS];
            button_state = new BState[NUMBER_OF_BUTTONS];
            button_texture = new Texture2D[NUMBER_OF_BUTTONS];
            button_timer = new double[NUMBER_OF_BUTTONS];
            button_functions = new Func<int, int, bool>[NUMBER_OF_BUTTONS];

            // starting x and y locations to stack buttons 
            // vertically in the middle of the screen
            int x = game.Window.ClientBounds.Width / 2 - BUTTON_WIDTH / 2;
            int y = game.Window.ClientBounds.Height / 2 -
                NUMBER_OF_BUTTONS / 2 * BUTTON_HEIGHT -
                (NUMBER_OF_BUTTONS % 2) * BUTTON_HEIGHT / 2;

            for (int i = 0; i < NUMBER_OF_BUTTONS; i++)
            {
                button_state[i] = BState.UP;
                button_color[i] = Color.White;
                button_enabled[i] = true;
                button_timer[i] = 0.0;
                button_rectangle[i] = new Rectangle(x, y, BUTTON_WIDTH, BUTTON_HEIGHT);
                y += BUTTON_HEIGHT;
            }

            background_color = Color.CornflowerBlue;

        }

        public virtual void LoadContent()
        {
        }

        public virtual void UnloadContent()
        {
        }

        public virtual void Update(GameTime gameTime)
        {
            // get elapsed frame time in seconds
            frame_time = gameTime.ElapsedGameTime.Milliseconds / 1000.0;

            /* handle button presses */
            TouchLocationState touchState = TouchLocationState.Released;

            GestureSample gesture;

            // update mouse variables
            while (TouchPanel.IsGestureAvailable)
            {
                gesture = TouchPanel.ReadGesture();
                if (gesture.GestureType == GestureType.Tap || gesture.GestureType == GestureType.Hold)
                {
                    touchLocation = gesture.Position;
                    touchState = TouchLocationState.Pressed;
                }
            }

            mx = (int)touchLocation.X;
            my = (int)touchLocation.Y;
            prev_mpressed = mpressed;
            mpressed = touchState == TouchLocationState.Pressed;

            update_buttons();
        }

        public virtual void Draw(GameTime gameTime)
        {
            for (int i = 0; i < NUMBER_OF_BUTTONS; i++)
                game.SpriteBatch.Draw(button_texture[i], button_rectangle[i], button_enabled[i] ? button_color[i] : Color.Gray);
            
        }

        /* Button Methods */

        // wrapper for hit_image_alpha taking Rectangle and Texture
        Boolean hit_image_alpha(Rectangle rect, Texture2D tex, int x, int y)
        {
            return hit_image_alpha(
                0,
                0,
                tex,
                tex.Width * (x - rect.X) / rect.Width,
                tex.Height * (y - rect.Y) / rect.Height
            );
        }

        // wraps hit_image then determines if hit a transparent part of image 
        Boolean hit_image_alpha(float tx, float ty, Texture2D tex, int x, int y)
        {
            if (hit_image(tx, ty, tex, x, y))
            {
                uint[] data = new uint[tex.Width * tex.Height];
                tex.GetData<uint>(data);

                if ((x - (int)tx) + (y - (int)ty) * tex.Width < tex.Width * tex.Height)
                {
                    return (
                        (data[(x - (int)tx) + (y - (int)ty) * tex.Width]
                        & 0xFF000000) >> 24) > 20;
                    /* 0xAARRGGBB */
                }
            }

            return false;
        }

        // determine if x,y is within rectangle formed by texture located at tx,ty
        Boolean hit_image(float tx, float ty, Texture2D tex, int x, int y)
        {
            return (x >= tx
                && x <= tx + tex.Width
                && y >= ty
                && y <= ty + tex.Height);
        }

        // determine state and color of button
        void update_buttons()
        {
            for (int i = 0; i < NUMBER_OF_BUTTONS; i++)
            {

                if (button_enabled[i] && hit_image_alpha(button_rectangle[i], button_texture[i], mx, my))
                {
                    button_timer[i] = 0.0;
                    if (mpressed)
                    {
                        // mouse is currently down
                        button_state[i] = BState.DOWN;
                        button_color[i] = Color.Red;
                    }
                    else if (!mpressed && prev_mpressed)
                    {
                        // mouse was just released
                        if (button_state[i] == BState.DOWN)
                        {
                            // button i was just down
                            button_state[i] = BState.JUST_RELEASED;
                        }
                    }
                    else
                    {
                        button_state[i] = BState.HOVER;
                        button_color[i] = Color.White;
                    }
                }
                else
                {
                    button_state[i] = BState.UP;
                    if (button_timer[i] > 0)
                    {
                        button_timer[i] = button_timer[i] - frame_time;
                    }
                    else
                    {
                        button_color[i] = Color.White;
                    }
                }

                if (button_state[i] == BState.JUST_RELEASED)
                {
                    take_action_on_button(i);
                }
            }
        }

        // Logic for each button click goes here
        protected virtual void take_action_on_button(int i)
        {
            button_functions[i](i, 0);
        }

        
    }
}
